package pacman;

import java.awt.Graphics;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import javax.swing.JFrame;
import javax.swing.JPanel;

/**
 * This class handles all inputs from keyboard and mouse and all the output to screen
 * @author Carlos Massera Filho
 */
public class InputOutput extends JFrame
{
  int X = 0, Y = 0;
  private boolean[] keyboardBuffer;
  private boolean[] mousebutton;
  int notches;

  private int windowSizeX,
              windowSizeY;

  Maps mapBuffer;
  Characters charactersBuffer;

  /**
   * This function start the window and the keyboard and mouse listener
   * @param sizeX
   * @param sizeY
   */
  public InputOutput(int sizeX, int sizeY)
  {
    this.windowSizeX = sizeX;
    this.windowSizeY = sizeY;
    getContentPane().add(new Draw());

    setSize(windowSizeX, windowSizeY);
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    setVisible(true);

    addKeyListener(new Keyboard());
    keyboardBuffer = new boolean[256];
    for (int i = 0; i < 256; i++)
    {
      keyboardBuffer[i] = false;
    }

    addMouseListener(new Mouse());
    mousebutton = new boolean[4];
    for (int i = 0; i < 4; i++)
        mousebutton[i] = false;

    addMouseWheelListener(new MouseWheel());
    notches = 0;
  }

  /**
   * Loads the buffer to render the map and characters
   * @param map Map to be rendered
   * @param chars Characters to be rendered
   */
  public void loadRenderBuffer(Maps map, Characters chars)
  {
    this.mapBuffer = map;
    this.charactersBuffer = chars;
  }
  
  /**
   * render map and characters
   * @param g Graphic interface where things will be rendered to
   */
  public void renderScreen(Graphics g)
  {
    if (mapBuffer != null)
      mapBuffer.renderMap(g);
    if (charactersBuffer != null)
      charactersBuffer.renderCharacters(g);
  }

  /**
   * verify if target key is pressed
   * @param i key index example: KeyEvent.VK_SPACE
   * @return true if is pressed false otherwise
   */
  public boolean getKeyboardBuffer(int i) {
      return keyboardBuffer[i];
  }

  /**
   * set the keyboard buffer value
   * @param i key index example: KeyEvent.VK_SPACE
   * @param b the value to be set the keuboardbuffer
   */
  public void setKeyboardBuffer(int i, boolean b) {
    keyboardBuffer[i] = b;
  }

  /**
   * get if the mouse button is clicked and set it to not clicked
   * @param i button to verify
   * @return true if button is pressed false otherwise
   */
  public boolean getMouseButton(int i){
    mousebutton[3] = mousebutton[i];
    mousebutton[i] = false;
    return mousebutton[3];
  }

  /**
   * Verify the mouse wheel rolling
   * @return > 0 if it scrolls down and < 0 if it scrolls up
   */
  public int getMouseWheel(){
    int aux_notches;

    aux_notches = notches;
    notches = 0;

    return aux_notches;
  }

  class Keyboard implements KeyListener
  {
    public void keyPressed(KeyEvent e)
    {
      InputOutput.this.keyboardBuffer[e.getKeyCode()] = true;
    }

    public void keyReleased(KeyEvent e)
    {
      InputOutput.this.keyboardBuffer[e.getKeyCode()] = false;
    }

    public void keyTyped(KeyEvent e){};
  }

  class Mouse implements MouseListener
  {
    public void mouseClicked(MouseEvent e)
    {
      InputOutput.this.X = e.getX() - 8;
      InputOutput.this.Y = e.getY() - 29;
      InputOutput.this.repaint();
    }

    public void mouseEntered(MouseEvent e){}
    public void mouseExited(MouseEvent e){}

    public void mousePressed(MouseEvent e)
    {
      switch(e.getModifiers())
      {
        case InputEvent.BUTTON1_MASK:
          mousebutton[0] = true;
        break;

        case InputEvent.BUTTON2_MASK:
          mousebutton[1] = true;
        break;

        case InputEvent.BUTTON3_MASK:
          mousebutton[2] = true;
        break;
      }
    }

   public void mouseReleased(MouseEvent e)
    {
      switch(e.getModifiers()) {
          case InputEvent.BUTTON1_MASK:
            mousebutton[1] = false;
          break;

          case InputEvent.BUTTON2_MASK:
            mousebutton[2] = false;
          break;

          case InputEvent.BUTTON3_MASK:
            mousebutton[3] = false;
          break;
      }
    }
  }

  class MouseWheel implements MouseWheelListener{
    public void mouseWheelMoved(MouseWheelEvent e) {
      notches = e.getWheelRotation();
    }
  }

  /**
   *
   */
  public class Draw extends JPanel
  {
    @Override
    protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      InputOutput.this.renderScreen(g);
    }
  }
}
